/*
 *
 *  * Copyright (c) 2016. For Intelligent Group.
 *
 */

package com.intelligent.ispc.chart.grr;

import com.intelligent.ispc.common.utils.MathUtils;
import com.intelligent.ispc.foundation.chart.AbstractChart;
import com.intelligent.ispc.foundation.chart.axis.FixedNumberAxis;
import com.intelligent.ispc.foundation.chart.util.ChartColor;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.StandardXYItemLabelGenerator;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.Range;
import org.jfree.data.xy.IntervalXYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleInsets;

import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.text.DecimalFormat;
import java.util.List;
import java.util.ArrayList;

/**
 * Created by cherry on 2016/8/31.
 * Modified by QiangChen on 2016/11/7.
 */
public class RPlotChart extends AbstractChart {

    private IntervalXYDataset dataset;
    private JFreeChart localChart;
    private String chartType;
    private int part;
    private int trial;
    private double[] value;
    private String chartName;
    private boolean isDataValid;

    /**
     * @param value     The value in R&R Plot - By Appraisers represents the test value for each person and the value in R&R Plot - By Parts represents the test values for each sample.
     * @param chartType is used to indicate whether R&R Plot - By Appraisers or R&R Plot - By Parts.
     * @param part      indicates the type of the product.
     * @param trial     indicates the number of tests.
     */
    public RPlotChart(double[] value, String chartType, int part, int trial) {
        this.isDataValid = true;
        this.chartName = chartType;
        this.value = value;
        this.part = part;
        this.trial = trial;
        this.chartType = chartType;
        dataset = createDataset(value);
    }

    @Override
    protected JFreeChart buildChart() {
        if (!isDataValid) {
            return this.blankChart(chartName);
        }

        localChart = ChartFactory.createXYLineChart(chartType, "", "", dataset, PlotOrientation.VERTICAL, true, true, false);
        XYPlot localXYPlot = (XYPlot) localChart.getPlot();
        localXYPlot.setDomainPannable(true);
        localXYPlot.setRangePannable(true);

        NumberAxis xAxis = (NumberAxis) localXYPlot.getDomainAxis();
        xAxis.setAutoTickUnitSelection(false);

        XYLineAndShapeRenderer localXYLineAndShapeRenderer = new XYLineAndShapeRenderer();
        localXYLineAndShapeRenderer.setSeriesLinesVisible(0, true);
        localXYLineAndShapeRenderer.setSeriesShapesVisible(0, true);
        localXYLineAndShapeRenderer.setSeriesLinesVisible(1, false);
        localXYLineAndShapeRenderer.setSeriesShapesVisible(1, true);
        localXYLineAndShapeRenderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());
        final int defaultEntityRadius = 6;
        localXYLineAndShapeRenderer.setDefaultEntityRadius(defaultEntityRadius);

        localXYLineAndShapeRenderer.setSeriesPaint(0, ChartColor.RED);
        localXYLineAndShapeRenderer.setSeriesFillPaint(0, ChartColor.RED);
        localXYLineAndShapeRenderer.setSeriesPaint(1, ChartColor.ORANGE);
        localXYLineAndShapeRenderer.setSeriesFillPaint(1, ChartColor.ORANGE);
        localXYLineAndShapeRenderer.setBaseShapesVisible(true);
        localXYLineAndShapeRenderer.setDrawOutlines(true);
        localXYLineAndShapeRenderer.setUseFillPaint(true);

        final float seriesStroke = 1.0F;
        final float seriesOutlineStroke = 0.5F;
        final Ellipse2D ellipse2D = new Ellipse2D.Double(-2.0D, -2.0D, 4.0D, 4.0D);
        localXYLineAndShapeRenderer.setSeriesStroke(0, new BasicStroke(seriesStroke));
        localXYLineAndShapeRenderer.setSeriesOutlineStroke(0, new BasicStroke(seriesOutlineStroke));
        localXYLineAndShapeRenderer.setSeriesShape(0, ellipse2D);
        localXYLineAndShapeRenderer.setSeriesStroke(1, new BasicStroke(seriesStroke));
        localXYLineAndShapeRenderer.setSeriesOutlineStroke(1, new BasicStroke(seriesOutlineStroke));
        localXYLineAndShapeRenderer.setSeriesShape(1, ellipse2D);
        localXYLineAndShapeRenderer.setBaseItemLabelGenerator(new StandardXYItemLabelGenerator());
        localXYLineAndShapeRenderer.setBaseItemLabelsVisible(false);
        localXYLineAndShapeRenderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator("({1}, {2})", new DecimalFormat(""), new DecimalFormat(this.getDigNumFormat())));

        localXYPlot.setRenderer(localXYLineAndShapeRenderer);

        FixedNumberAxis axis = new FixedNumberAxis();
        axis.setTickLabelInsets(new RectangleInsets(10, 0, 10, 0));
        List<Double> data = new ArrayList<Double>();
        for (int i = 0; i < value.length; i++) {
            if (!Double.isNaN(value[i])) {
                data.add(value[i]);
            }
        }

        //The maximum and minimum values are calculated to limit the range of Y coordinates
        double min = 0;
        double max = 0;

        if (data != null && data.size() != 0) {
            min = MathUtils.findMin(data);
            max = MathUtils.findMax(data);
        }

        if (max != min) {
            final double factor = 0.20;
            double reserve = (max - min) * factor;
            axis.setR(new Range(min - reserve, max + reserve));
            localXYPlot.setRangeAxis(axis);
        }

        FixedNumberAxis domainAxis = new FixedNumberAxis();
        domainAxis.setR(localXYPlot.getDomainAxis().getRange());
        domainAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        localXYPlot.setDomainAxis(domainAxis);

        return localChart;
    }

    /*
    * Create dataset for R&R Plot, and the abnormal data is processed as necessary.
    * */
    private IntervalXYDataset createDataset(double[] value) {

        if (value == null) {
            isDataValid = false;
        } else {
            int k = 1;
            int size = part * trial + 1;

            String serial1 = "Value";
            String serial2 = "R&R Plot – By Appraisers".equals(chartType) ? "Avg" : "Total Mean";

            XYSeries localXYSeries1 = new XYSeries(serial2);
            XYSeries localXYSeries2 = new XYSeries(serial1);
            for (int i = 0; i < value.length; i++) {
                if (Double.isNaN(value[i])) {
                    continue;
                } else if ((i + 1) % size == 0) {
                    localXYSeries1.add(k, value[i]);
                    k++;
                } else {
                    localXYSeries2.add(k, value[i]);
                }
            }

            XYSeriesCollection localXYSeriesCollection = new XYSeriesCollection();
            localXYSeriesCollection.addSeries(localXYSeries1);
            localXYSeriesCollection.addSeries(localXYSeries2);
            return localXYSeriesCollection;
        }
        return null;
    }
}

